package net.israfil.service.mail.api.smtp;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import net.israfil.service.mail.api.MailAddress;
import net.israfil.service.mail.api.MailHeader;
import net.israfil.service.mail.api.MailMessage;
import net.israfil.service.mail.api.MailMessageBody;
import net.israfil.service.mail.api.smtp.header.AbstractSMTPHeader;
import net.israfil.service.mail.api.smtp.header.SMTPAddressHeader;
import net.israfil.service.mail.api.smtp.header.SMTPAddressesHeader;
import net.israfil.service.mail.api.smtp.header.SMTPStringHeader;


public class SMTPMessage implements MailMessage {
	
	private final Map<String,MailHeader<?>> headers;
	private MailMessageBody body;
	
	public SMTPMessage() {
		this(null,null);
	}
	
	protected SMTPMessage(Collection<AbstractSMTPHeader<?>> headers) {
		this(headers,null);
	}
	
	protected SMTPMessage(Collection<AbstractSMTPHeader<?>> headers, MailMessageBody body) {
		this.headers = new HashMap<String,MailHeader<?>>();
		if (headers != null) this.addHeaders(headers);
		this.setBody(body);
	}
	
	private Object getHeaderValue(String name,Map<String, MailHeader<?>> headers) {
		MailHeader<?> h = headers.get(name);
		if (h == null) return null;
		else return h.getContent();
	}

	public void addAddress(SMTPHeaderTypes type, SMTPAddress... addresses) {
		switch (type) {
			case From: 
				throw new IllegalArgumentException("You may not set the From: header from the addAddress method - use setFromAddress() instead.");
			case Subject:
				throw new IllegalArgumentException("You may not set the Subject: header from the addAddress method - use setSubject() instead.");
			case To: case Bcc: case Cc: 
				SMTPAddressesHeader header = (SMTPAddressesHeader)headers.get(type.getCanonicalRepresentation());
				if (header == null) {
					header = new SMTPAddressesHeader(
							type.getCanonicalRepresentation(),
							new ArrayList<SMTPAddress>()
					);
					headers.put(type.getCanonicalRepresentation(), header);
				}
				Collection<SMTPAddress> _addresses = header.getContent();
				for (SMTPAddress address : addresses) {
					_addresses.add(address);
				}
				break;
		}
	}
	public void clearAddresses(SMTPHeaderType type) {
		headers.put(type.getCanonicalRepresentation(), new SMTPAddressesHeader(
				type.getCanonicalRepresentation(),
				new ArrayList<SMTPAddress>()
		));
	}

	@SuppressWarnings("unchecked")
	public Collection<MailAddress> getBccAddresses() {
		return (Collection<MailAddress>)getHeaderValue(SMTPHeaderTypes.Bcc.getCanonicalRepresentation(),headers);
	}
	
	@SuppressWarnings("unchecked")
	public Collection<MailAddress> getToAddresses() {
		return (Collection<MailAddress>)getHeaderValue(SMTPHeaderTypes.To.getCanonicalRepresentation(),headers);
	}
	
	@SuppressWarnings("unchecked")
	public Collection<MailAddress> getCcAddresses() {
		return (Collection<MailAddress>)getHeaderValue(SMTPHeaderTypes.Cc.getCanonicalRepresentation(),headers);
	}

	public MailMessageBody getBody() {
		return body;
	}

	public void setBody(MailMessageBody body) {
		if (body == null) this.body = new PlaintextMessageBody();
		else this.body = body;
	}

	public MailAddress getFromAddress() {
		return (SMTPAddress)getHeaderValue(SMTPHeaderTypes.From.getCanonicalRepresentation(),headers);
	}

	public void setFromAddress(SMTPAddress address) {
		headers.put(SMTPHeaderTypes.From.getCanonicalRepresentation(),
			new SMTPAddressHeader(SMTPHeaderTypes.From.getCanonicalRepresentation(),address)
		);
	}

	public String getSubject() {
		return (String)getHeaderValue(SMTPHeaderTypes.Subject.getCanonicalRepresentation(),headers);
	}
	
	public void setSubject(String subject) {
		headers.put(SMTPHeaderTypes.Subject.getCanonicalRepresentation(),
			new SMTPStringHeader(SMTPHeaderTypes.Subject.getCanonicalRepresentation(),subject)
		);
	}

	public Map<String,MailHeader<?>> getHeaders() { 
		return new HashMap<String,MailHeader<?>>(headers); 
	}
	
	public void addHeader(AbstractSMTPHeader<?>...headers) {
		addHeaders(Arrays.asList(headers));
	}
	
	public void addHeaders(Collection<AbstractSMTPHeader<?>> headers) {
		for (MailHeader<?> header : headers) {
			SMTPHeaderTypes type = null;
			try {
				 type = SMTPHeaderTypes.valueOfCanonicalString(header.getName());
			} catch (IllegalArgumentException e) {
				// NO-OP if not a member of this enumerated 
			}
			SMTPUtils.validateSpecialHeader(type, header);
			this.headers.put(header.getName(), header);	
		}
	}

	
	public void clearHeaders() {
		this.headers.clear();
	}
	
	public MailHeader<?> removeHeader(String name) {
		return this.headers.remove(name);
	}

	public MailHeader<?> getHeader(String name) {
		return this.headers.get(name);
	}
	
	public String getType() {
		return SMTPTransport.TRANSPORT_TYPE;
	}


}
